package netmorph.optimization;

import model.optimization.PartOptimizer;
import static optimization.LinearAlgebra.*;
import theory.vanpelt.bifurcation.BEFindValues;
import model.AbstractModel;
import optimization.OldLogger;
import optimization.NelderMeadStateMachine;
import optimization.RetrospectiveApproximation;

public class RABESPartOptimizer extends PartOptimizer {

	public String getName() {
		return "BES/PO/RA";
	}

	VectorFunction beCons = new VectorFunction() {
		@Override
		public int yDim() {
			return 2;
		}
		@Override
		public double[] evaluate(double[] p) {
			if (p[0] < 1) p[0] = 1;
			if (p[0] > 6) p[0] = 6;
			if (p[1] < 0) p[1] = 0;
			if (p[1] > 1) p[1] = 1;
			return p;
		}
	};

	double[] h = new double[]{ 0.1, 0.05};

	RetrospectiveApproximation ra;
	NelderMeadStateMachine nm;

	int MAX_ITER_RA = 10;
	boolean done = false;
	
	@Override
	public void init() {
		super.init();
		
		// init RA
		double[] xinit = BEFindValues.find(modelPart.yt[0], modelPart.yt[1]);
		ra = new RetrospectiveApproximation(null, beCons, xinit, h) {
			protected int sampleSize(int iter)
			{
				return (int)(200*Math.pow(2,iter)); 
			}
		};

		// FIXME TEMP skip to RA2
		ra.iter+=2;
		ra.xa = new double[]{ 1.90544, 0.09106};
		// ----
		
		ra.beginIteration();

		OldLogger.format("RA%d   X %.5f, %.5f   (N=%d, rnd=%d, h=%.5f, nu=%.5f)", (ra.iter+1), ra.xa[0], ra.xa[1], ra.N, ra.randSeed, ra.hscale, ra.term);
		
		// init NM
		Function g = new PointDistanceFunction(modelPart.yt);
		nm = new NelderMeadStateMachine(g, beCons);
		nm.enableS9RSModifications();
		nm.setStochasticParameters(ra.N);//, ra.randSeed);
		nm.initSearch(ra.xa, vMul(ra.hscale, h));		
		
		// set initial x
		modelPart.x = nm.getX();
	}
	
	@Override
	public void modelComputed(AbstractModel model) {
		super.modelComputed(null);

		if (done) { return; }

		
		// update nelder-mead
		nm.modelComputed(modelPart.xDist);
		modelPart.x = nm.getX();

		
		// Nelder-Mead done ?
		if (nm.isDone()) {

			// show stats
			ra.xa = nm.getRoot();
			OldLogger.format("RA%d   X %.5f, %.5f   (N=%d, rnd=%d, h=%.5f, nu=%.5f)", (ra.iter+1), ra.xa[0], ra.xa[1], ra.N, ra.randSeed, ra.hscale, ra.term);
			ra.endIteration();

			if (ra.iter >= MAX_ITER_RA) {
				// RA done
				done = true;
				modelPart.x = ra.estimateRoot();
				OldLogger.format("RA--   X %.5f, %.5f   ", modelPart.x[0], modelPart.x[1]);
				return;
			}
			
			ra.beginIteration();
			nm.setStochasticParameters(ra.N);//, ra.randSeed);
			nm.initSearch(ra.xa, vMul(ra.hscale, h));		
			modelPart.x = nm.getX();
		}		
		
	}
	
	@Override
	public boolean isDone() {
		return done;
	}
}
